#!/usr/bin/env python3
""" SoLoud Ruby wrapper generator """

import soloud_codegen

fo = open("../glue/soloud.rb", "w")

#   module SoLoudImporter
#       extend DL::Importer
#       dlload 'soloud_x86.dll'
#
#       extern "char * foo(int, float)"
#
#       CONSTANT = 23
#   end
#

SOLOUD_TYPES = []

for x in soloud_codegen.soloud_type:
    SOLOUD_TYPES.append(x + " *")


def pythonize_camelcase(origstr):
    """ Turns camelCase into underscore_style """
    ret = ""
    for letter in origstr:
        if letter.isupper():
            ret += '_' + letter.lower()
        else:
            ret += letter
    # kludge, because calc_f_f_t is silly.
    ret = ret.replace("_f_f_t", "_fft")
    # kludge for 3d calls
    ret = ret.replace("3d", "_3d")
    return ret

def has_ex_variant(funcname):
    """ Checks if this function has an "Ex" variant """    
    if funcname[-2::] == "Ex":
        # Already an Ex..
        return False
    for func in soloud_codegen.soloud_func:
        if func[1] == (funcname + "Ex"):
            return True
    return False

fo.write("# SoLoud wrapper for Ruby\n")
fo.write("# This file is autogenerated; any changes will be overwritten\n")
fo.write("\n")
fo.write('require "dl/import"\n')
fo.write("\n")
fo.write('module SoLoudImporter\n')
fo.write('\textend DL::Importer\n')
fo.write("\tdlload 'soloud_x86.dll'\n")
fo.write("\n")

fo.write("\t# Enumerations\n")
for x in soloud_codegen.soloud_enum:
    fo.write('\t' + x + '=' + str(soloud_codegen.soloud_enum[x])+ '\n')
fo.write("\n")
fo.write("\t# Raw DLL functions\n")

for x in soloud_codegen.soloud_func:
    fo.write('\textern "' + x[0] + ' ' + x[1] + '(')
    first = True
    for y in x[2]:
        if len(y) > 0:
            if first:
                first = False
            else:
                fo.write(", ")
            fo.write(y[0])
    fo.write(')"\n')

fo.write('end\n')
fo.write('\n')

#################################################################
#
# oop
#

#   class Soloud
#       @clshandle
#       def initialize(args)
#           @clshandle = SoLoudImporter.soloud_create()
#       end
#       def destroy()
#           SoLoudImporter.soloud_destroy(@clshandle)
#       end
#       def foobar(a,b)
#           SoLoudImporter.foobar(@clshandle,a,b)
#       end
#   end
#

fo.write('\n')
fo.write('# OOP wrappers\n')

def fix_default_param(defparam, classname):
    """ 'fixes' default parameters from C to what python expectes """
    if (classname + '::') == defparam[0:len(classname)+2:]:
        return defparam[len(classname)+2::]
    if defparam[len(defparam)-1] == "f":
        return defparam[0:len(defparam)-1]
    return defparam

for x in soloud_codegen.soloud_type:
    first = True
    for y in soloud_codegen.soloud_func:
        if (x + "_") == y[1][0:len(x)+1:]:
            if first:
                fo.write('\n')
                fo.write('class %s\n'%(x))
                fo.write('\t@objhandle=nil\n')
                fo.write('\tattr_accessor :objhandle\n')
                for z in soloud_codegen.soloud_enum:
                    if z[0:len(x)+1] == x.upper()+'_':
                        s = str(soloud_codegen.soloud_enum[z])
                        fo.write('\t%s=%s\n'%(z[len(x)+1::], s))
                fo.write('\tdef initialize(args)\n')
                fo.write('\t\t@objhandle = SoLoudImporter.%s_create()\n'%(x))
                fo.write('\tend')
                fo.write('\n')
                fo.write('\tdef destroy()\n')
                fo.write('\t\tSoLoudImporter.%s_destroy(@objhandle)\n'%(x))
                fo.write('\tend')
                fo.write('\n')
                
                first = False
            funcname = y[1][len(x)+1::]
            # If the function has the name "Ex", remove the subfix
            if funcname[-2::] == "Ex":
                funcname = funcname[:len(funcname)-2]
            # Skip generating functions that have an Ex variant            
            if funcname == "create" or funcname == "destroy" or has_ex_variant(y[1]):
                pass # omit create/destroy, handled by initialize/destroy
            else:
                fo.write('\tdef %s('%(pythonize_camelcase(funcname)))
                firstparam = True
                for z in y[2]:
                    if len(z) > 1:
                        if z[1] == 'a'+x:
                            pass # skip the 'self' pointer
                        else:
                            if firstparam:
                                firstparam = False
                            else:
                                fo.write(', ')
                            fo.write(z[1])
                            if len(z) > 2:
                                fo.write("=" + fix_default_param(z[2], x)+"")
                fo.write(')\n')
                fo.write('\t\t')
                fo.write('SoLoudImporter.' + y[1] + '(@objhandle')
                for z in y[2]:
                    if len(z) > 1:
                        if z[1] == 'a'+x:
                            pass # skip the 'self' pointer
                        else:
                            fo.write(', ')
                            if z[0] in SOLOUD_TYPES:
                                fo.write(z[1] + '.objhandle')
                            else:
                                fo.write(z[1])
                fo.write(')\n')            
                fo.write('\tend\n')
    if not first:
        fo.write('end\n')

print("soloud.rb generated")

fo.close()
